<?php
/**
 * Created by PhpStorm.
 * User: jaylen
 * Date: 2020-06-05
 * Time: 14:51
 */

namespace app\common\model;

use app\common\enum\OrderEnum;
use app\common\exception\OrderException;
use app\common\exception\ParameterException;
use app\common\model\traits\HandleOrderExcelData;
use app\common\model\traits\HandleOrderExpress;
use app\common\model\traits\HandleUserOrder;
use app\common\model\traits\HandleUserShopOrder;
use app\common\validate\IDMustBeRequire;
use app\common\validate\Order as Validate;
use think\model\concern\SoftDelete;

class Order extends BaseModel
{
    protected $hidden = ['update_time','delete_time'];

    // 使用软删除
    use SoftDelete;
    protected $deleteTime = 'delete_time';

    private const WX_PAY_OPTIONS_PREFIX = 'tn_shop_order_';
    private const WX_PAY_OPTIONS_EXPIRE = 2000;

    public function user()
    {
        return $this->belongsTo('WeChatUser','user_id','id')
            ->field(['id','nick_name','avatar_url','openid']);
    }

    public function address()
    {
        return $this->belongsTo('OrderAddress', 'address_id','id');
    }

    public function product()
    {
        return $this->hasMany('OrderProduct', 'order_id','id');
    }

    public function express()
    {
        return $this->hasOne('OrderExpress','order_id','id');
    }

    /**
     * 为图片添加域名前缀
     * @param $value
     * @param $data
     * @return array
     */
    public function getImgUrlAttr($value, $data)
    {
        return [
            'value' => $value,
            'prefix' => $this->prefixImgUrl($value)
        ];
    }

    /**
     * 格式化支付创建时间
     * @param $value
     * @param $data
     * @return false|string
     */
    public function getPayTimeAttr($value, $data)
    {
        //设置时区，不设置的话，会与北京时间相差8小时
        date_default_timezone_set("PRC");
        if (empty($value)) {
            return '';
        }
        return date('Y-m-d H:i:s',$value);
    }

    /**
     * 格式化发货创建时间
     * @param $value
     * @param $data
     * @return false|string
     */
    public function getDeliveryTimeAttr($value, $data)
    {
        //设置时区，不设置的话，会与北京时间相差8小时
        date_default_timezone_set("PRC");
        if (empty($value)) {
            return '';
        }
        return date('Y-m-d H:i:s',$value);
    }

    /**
     * 格式化用户申请退款时间
     * @param $value
     * @param $data
     * @return false|string
     */
    public function getUserApplicationRefundTimeAttr($value, $data)
    {
        //设置时区，不设置的话，会与北京时间相差8小时
        date_default_timezone_set("PRC");
        if (empty($value)) {
            return '';
        }
        return date('Y-m-d H:i:s',$value);
    }

    /**
     * 格式化订单结束时间
     * @param $value
     * @param $data
     * @return false|string
     */
    public function getOrderEndTimeAttr($value, $data)
    {
        //设置时区，不设置的话，会与北京时间相差8小时
        date_default_timezone_set("PRC");
        if (empty($value)) {
            return '';
        }
        return date('Y-m-d H:i:s',$value);
    }

    /**
     * 格式化退款创建时间
     * @param $value
     * @param $data
     * @return false|string
     */
    public function getRefundCreateTimeAttr($value, $data)
    {
        //设置时区，不设置的话，会与北京时间相差8小时
        date_default_timezone_set("PRC");
        if (empty($value)) {
            return '';
        }
        return date('Y-m-d H:i:s',$value);
    }

    use HandleUserOrder;
    use HandleUserShopOrder;
    use HandleOrderExpress;
    use HandleOrderExcelData;

    /**
     * 获取订单的列表分页数据
     * @param array $params
     * @return mixed
     */
    public static function getPaginationList(array $params)
    {
        static::validatePaginationData($params);

        $static = new static;
        $static = $static->order('o.create_time','DESC');

//        $static = $static->alias('o')
//            ->join('we_chat_user u','o.user_id=u.id')
//            ->join('order_product op', 'op.order_id = o.id')
//            ->field([
//                'o.id',
//                'o.title',
//                'o.img_url',
//                'o.order_no',
//                'o.out_order_no',
//                'o.amount',
//                'o.refund_amount',
//                'o.type',
//                'o.status',
//                'u.nick_name',
//                'u.avatar_url',
//                'op.virtual_product'
//            ]);

        $static = $static->alias('o')
            ->join('we_chat_user u','o.user_id=u.id','left')
            ->join('order_product op', 'op.order_id = o.id AND o.type <> 1','left')
            ->field([
                'o.id',
                'o.title',
                'o.img_url',
                'o.order_no',
                'o.out_order_no',
                'o.amount',
                'o.refund_amount',
                'o.type',
                'o.status',
                'u.nick_name',
                'u.avatar_url',
                'op.virtual_product'
            ]);

        foreach ($params as $name => $value) {
            $value = !is_array($value) ? trim($value) : $value;

            switch ($name) {
                case 'nick_name':
                    if (!empty($value)) {
                        $likeText = "from_base64(u.nick_name) like '%{$value}%'";
                        $static = $static->whereRaw($likeText);
                    }
                    break;
                case 'title':
                    if (!empty($value)) {
                        $like_text = '%' . $value . '%';
                        $static = $static->whereLike('o.title',$like_text);
                    }
                    break;
                case 'order_no':
                    if (!empty($value)) {
                        $like_text = '%' . $value . '%';
                        $static = $static->whereLike('o.order_no',$like_text);
                    }
                    break;
                case 'out_order_no':
                    if (!empty($value)) {
                        $like_text = '%' . $value . '%';
                        $static = $static->whereLike('o.out_order_no',$like_text);
                    }
                    break;
                case 'type':
                    if (!empty($value)) {
                        $static = $static->where('o.type','=',intval($value));
                    }
                    break;
                case 'status':
                    if (!empty($value)) {
                        $static = $static->where('o.status','=',intval($value));
                    }
                    break;
                case 'sort_order':
                    if (!empty($value)) {
                        $static = $static->order($params['sort_prop'], $value == 'descending' ? 'desc' : 'asc');
                    }
                    break;
            }
        }

        return $static->paginate([
            'page' => $params['page'],
            'list_rows' => $params['limit'],
        ], false)
            ->withAttr('nick_name',function($value, $data){
                return base64_decode($value);
            });
    }

    /**
     * 根据id获取订单的后台详细信息
     * @param $id
     * @return array
     */
    public static function getOrderBackendByID($id)
    {
        $validate = new IDMustBeRequire();
        if (!$validate->check(['id'=>$id])) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        $order = static::with(['address','product','express'])
            ->where([['id','=',$id]])
            ->find();

        return $order ?: [];
    }

    /**
     * 根据订单编号获取指定字段的数据
     * @param $order_no
     * @param array $field
     * @param bool $get_product_data
     * @param array $product_field
     * @return array
     */
    public static function getOrderDataByOrderNo($order_no, $field = ['title','amount','create_time'], $get_product_data = false, $product_field = [])
    {
        $static = new static;
        $with_data = ['user'];

        // 合并数组
        $field = array_merge(['id','user_id','order_no'],$field);

        // 是否需要获取商品数据
        if ($get_product_data) {
            $product_field = array_merge(['order_id'], $product_field);
            $with_data['product'] = function ($query) use ($product_field) {
                $query->field($product_field);
            };
        }

        return $static->with($with_data)
            ->field($field)
            ->where('order_no','=',$order_no)
            ->find()
            ->toArray();
    }

    /**
     * 根据订单id获取指定字段的数据
     * @param $order_no
     * @param array $field
     * @return array
     */
    public static function getOrderDataById($id, $field = ['title','amount','create_time'])
    {
        $static = new static;

        // 合并数组
        $field = array_merge(['user_id','id'],$field);

        return $static->with(['user'])
            ->field($field)
            ->where('id','=',$id)
            ->find()
            ->toArray();
    }

    /**
     * 根据订单编号检查当前订单是否为指定的状态
     * @param $order_no
     * @param $check_status
     * @return bool
     */
    public static function checkOrderStatusByOrderNo($order_no,$check_status)
    {
        $orderData = self::getOrderDataByOrderNo($order_no,['status']);

        // 判断是否有该订单，如果没有直接返回false
        if (empty($orderData)) {
            return false;
        }

        $checkArray = [];
        if (!is_array($check_status)) {
            $checkArray[] = $check_status;
        } else {
            $checkArray = $check_status;
        }

        if (!in_array($orderData['status'],$checkArray)) {
            return false;
        }

        return true;

    }

    /**
     * 根据商品的规格id判断对应的订单状态是否存在
     * @param $product_specs_id
     * @param $check_status
     * @return array|bool
     */
    public static function checkOrderStatusByProductSpecsID($product_specs_id, $check_status)
    {
        // 获取当前用户的user_id
        $user_id = MpApiUserToken::getCurrentUID();

        // 判断待检查的状态是否为数组
        $checkArray = !is_array($check_status) ? [$check_status] : $check_status;

        // 查找数据库中是否存在对应的订单规格和状态匹配
        $product_where = OrderProduct::where('specs_id',$product_specs_id);
        $order = static::hasWhere('product', $product_where)
            ->where([
                ['user_id','=',$user_id],
                ['status','in',$checkArray]
            ])
            ->field('id,order_no,title')
            ->find();

        if (empty($order)) {
            return false;
        } else {
            return $order->toArray();
        }
    }

    /**
     * 创建订单信息
     * @param $params
     * @return mixed
     */
    public static function addOrder($params)
    {

        // 添加status的值为创建订单状态
        $params['status'] = isset($params['status']) ? $params['status'] : OrderEnum::CREATE_ORDER;

        $validate = new Validate();
        if (!$validate->scene('add')->check($params)) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        $static = new static;
        if ($static->allowField(['user_id',
                'title','img_url','freight',
                'order_no','prepay_id','amount','allow_pay_subscribe','allow_refund_subscribe','allow_submit_success_subscribe','allow_pay_timeout_subscribe','type','status'])
                ->save($params) === false) {
            throw new OrderException([
                'msg' => '创建订单错误',
                'errorCode' => 50001,
            ]);
        }

        return $static->id;
    }

    /**
     * 根据订单编号修改订单的信息
     * @param $orderNo 订单编号
     * @param $field 允许更新的字段信息
     * @param $data 需要更新的数据
     */
    public static function updateByOrderNo($orderNo, $field, $data)
    {
        $static = static::where('order_no','=',$orderNo)->find();

        if (empty($static)) {
            throw new OrderException();
        }

        if ($static->allowField($field)->save($data) === false) {
            throw new \Exception('更新订单信息失败');
        }
    }

    /**
     * 对虚拟商品的订单做已服务处理
     * @param $data
     * @return bool
     */
    public static function serveVirtualProductOrder($data)
    {
        $validate = new Validate();
        if (!$validate->scene('serve_virtual_order')->check($data)) {
            throw new ParameterException([
                'msg' => $validate->getError(),
            ]);
        }

        // 修改订单的状态为用户已签收
        try {
            $order = static::find($data['id']);
            $delivery_time = time();
            $order->allowField(['id','order_no','status','delivery_time'])
                ->save([
                    'status' => OrderEnum::SHIP_ORDER,
                    'delivery_time' => $delivery_time
                ]);
            self::createReceiptsTimeoutQueue($delivery_time,$order['order_no']);
        } catch (\Exception $e) {
            return false;
        }

        return true;
    }
}